﻿using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace ClassBuilder
{
    public static class Extensions
    {
        /// <summary>
        /// 判断字符串是否为Null、空
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsEmpty(this string value)
        {
            return string.IsNullOrWhiteSpace(value);
        }


        /// <summary>
        /// 判断字符串是否不为Null、空
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool NotEmpty(this string value)
        {
            return !string.IsNullOrWhiteSpace(value);
        }


        /// <summary>
        /// 判断引用类型是Null
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsNull<T>(this T value)
            where T : class
        {
            return value == null;
        }

        /// <summary>
        /// 判断引用类型是不为Null
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool NotNull<T>(this T value)
           where T : class
        {
            return value != null;
        }




        /// <summary>
        /// 格式化
        /// </summary>
        /// <param name="value"></param>
        /// <param name="objs"></param>
        /// <returns></returns>
        public static string Format(this string value, params object[] objs)
        {
            if (value.IsEmpty())
            {
                return string.Empty;
            }
            return string.Format(value, objs);
        }


        /// <summary>
        /// 与字符串进行比较，忽略大小写
        /// </summary>
        /// <param name="value"></param>
        /// <param name="other"></param>
        /// <returns></returns>
        public static bool EqualsIgnoreCase(this string value, string other)
        {
            return value.Equals(other, StringComparison.OrdinalIgnoreCase);
        }

        /// <summary>
        /// 转换成Boolean
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool ToBool(this object s)
        {
            if (s == null) return false;
            s = s.ToString().ToLower();
            if (s.Equals(1) || s.Equals("1") || s.Equals("true") || s.Equals("是") || s.Equals("yes"))
                return true;
            if (s.Equals(0) || s.Equals("0") || s.Equals("false") || s.Equals("否") || s.Equals("no"))
                return false;

            Boolean.TryParse(s.ToString(), out bool result);
            return result;
        }


        /// <summary>
        /// 转为首字母大写
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string ToFirstUpperStr(this string value)
        {
            if (value.IsEmpty())
            {
                return string.Empty;
            }
            return value.Substring(0, 1).ToUpper() + value.Substring(1);
        }

        /// <summary>
        /// 转为首字母小写
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string ToFirstLowerStr(this string value)
        {
            if (value.IsEmpty())
            {
                return string.Empty;
            }
            return value.Substring(0, 1).ToLower() + value.Substring(1);
        }

        /// <summary>
        /// 字符串是关键字时格式化
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string KWFormat(this string value)
        {
            //https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/
            var keywords = new List<string>()
            {
                "abstract","as","base","bool",
                "break","byte","case","catch",
                "char","checked","class","const",
                "continue","decimal","default","delegate",
                "do","double","else","enum",
                "event","explicit","extern","false",
                "finally","fixed","float","for",
                "foreach","goto","if","implicit",
                "in","int","interface","internal",
                "is","lock","long","namespace",
                "new","null","object","operator",
                "out","override","params","private",
                "protected","public","readonly","ref",
                "return","sbyte","sealed","short",
                "sizeof","stackalloc","static","string",
                "struct","switch","this","throw",
                "true","try","typeof","uint",
                "ulong","unchecked","unsafe","ushort",
                "using","virtual","void","volatile",
                "while"
            };

            if (keywords.Contains(value))
            {
                return "@" + value;
            }
            return value;
        }

        /// <summary>
        /// 正确匹配URL的正则表达式
        /// https://www.cnblogs.com/speeding/p/5097790.html
        /// </summary>
        const string URL_Regex = "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";

        /// <summary>
        /// 对字符串进行处理，先进行html编码，再处理链接地址
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string HtmlHandle(this string value)
        {
            if (value.IsEmpty())
            {
                return string.Empty;
            }
            var strVal = HttpUtility.HtmlEncode(value);

            // 处理see文档标记：https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/xmldoc/see
            strVal = Regex.Replace(strVal, @"^((.|\n)*?)(" + URL_Regex + ")((.|\n)*?)$", "$1<see href=\"$3\"/>$5", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);

            return strVal;
        }


        /// <summary>
        /// 对字符串进行编码
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string HtmlEncode(this string value)
        {
            if (value.IsEmpty())
            {
                return string.Empty;
            }
            return HttpUtility.HtmlEncode(value);
        }

        /// <summary>
        /// 对字符串进行解码
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string HtmlDecode(this string value)
        {
            if (value.IsEmpty())
            {
                return string.Empty;
            }
            return HttpUtility.HtmlDecode(value);
        }

        /// <summary>
        /// 除去Html
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string NoHtml(this string value)
        {
            return Regex.Replace(value, @"<.+?>", "", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
        }

        /// <summary>
        /// 字符串的Md5值
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string Md5(this string value)
        {
            if (value == null)
                return null;
            MD5 md5Hash = MD5.Create();
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(value));
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString();
        }

        public static string NameStyle(this string value, NameRule rule)
        {
            if (rule == NameRule.Lower)
            {
                return value.ToFirstLowerStr();
            }
            else if (rule == NameRule.Upper)
            {
                return value.ToFirstUpperStr();
            }
            else //if (rule == NameRule.Normal)
            {
                return value;
            }
        }
    }
}
